package com.topone.service.impl;

import com.topone.Const.Model;
import com.topone.Enum.ResultEnum;
import com.topone.Exception.FanZoneException;
import com.topone.Utils.MapKeyComparatorUtil;
import com.topone.Utils.ServiceUtils;
import com.topone.VO.CountParam;
import com.topone.dataObject.Bussiness;
import com.topone.dataObject.Mapper.ProviderNotificationMapper;
import com.topone.dataObject.OrderDetail;
import com.topone.dto.BillDTO;
import com.topone.dto.ProviderNotificationDTO;
import com.topone.repository.BussinessRepository;
import com.topone.repository.OrderDetailRepository;
import com.topone.service.ProviderNotificationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
@Slf4j
public class ProviderNotifitionServiceImpl implements ProviderNotificationService {

    @Autowired
    private ProviderNotificationMapper providerNotificationMapper;

    @Autowired
    private BussinessRepository bussinessRepository;

    @Autowired
    private OrderDetailRepository orderDetailRepository;

    @Override
    public Map<String, Object> checkProviderBill(CountParam countParam) {
        if (Objects.isNull(countParam)) {
            log.error("无请求参数");
            throw new FanZoneException(ResultEnum.PARAM_IS_NULL);
        }
        if (StringUtils.isEmpty(countParam.getBusinessId())) {
            log.error("商家Id为空");
            throw new FanZoneException(ResultEnum.BUSINESS_ID_IS_NULL);
        }
        if (countParam.getPayStatus() == null) {
            countParam.setPayStatus(1);
        }
        countParam.setBusinessId(countParam.getBusinessId());
        if (StringUtils.isNotEmpty(countParam.getOpenid())) {
            countParam.setOpenid(countParam.getOpenid());
        }
        if (StringUtils.isNotEmpty(countParam.getStartDateText())) {
            try {
                Date date = ServiceUtils.getStandardFormatOnyyyyMMddHHmmss()
                        .parse(countParam.getStartDateText());
                countParam.setStartDate(date);
            } catch (Exception e) {
                log.error("日期转换错误", e.fillInStackTrace());
                throw new FanZoneException(ResultEnum.DATE_TRANSFER_ERROR);
            }
        }
        if (StringUtils.isNotEmpty(countParam.getEndDateText())) {
            try {
                Date date = ServiceUtils.getStandardFormatOnyyyyMMddHHmmss()
                        .parse(countParam.getEndDateText());
                countParam.setEndDate(date);
            } catch (Exception e) {
                log.error("日期转换错误", e.fillInStackTrace());
                throw new FanZoneException(ResultEnum.DATE_TRANSFER_ERROR);
            }
        }
        if (StringUtils.isNotEmpty(countParam.getDurationText())) {
            Date date = ServiceUtils.parse(ServiceUtils.getStandardFormatOnyyyyMMddHHmmss()
                    , ServiceUtils.getCurrentTimeOnyyyyMMddHHmmssText());
            Date startDate = null;
            switch (countParam.getDurationText()) {
                case Model.CHECK_BILL_ONE_HOUR: {
                    startDate = DateUtils.addHours(date, -1);
                    break;
                }
                case Model.CHECK_BILL_ONE_DAY: {
                    Calendar calendar=Calendar.getInstance();
                    calendar.setTime(new Date());
                    calendar.set(Calendar.HOUR_OF_DAY, 0);
                    calendar.set(Calendar.MINUTE, 0);
                    calendar.set(Calendar.SECOND, 0);
                    startDate = calendar.getTime();
                    break;
                }
                case Model.CHECK_BILL_THREE_DAY: {
                    startDate = DateUtils.addDays(date, -3);
                    break;
                }
                case Model.CHECK_BILL_SEVEN_DAY: {
                    startDate = DateUtils.addWeeks(date, -1);
                    break;
                }
                case Model.CHECK_BILL_ONE_MONTH: {
                    startDate = DateUtils.addMonths(date, -1);
                    break;
                }
                case Model.CHECK_BILL_THREE_MONTH: {
                    startDate = DateUtils.addMonths(date, -3);
                    break;
                }
                case Model.CHECK_BILL_HALF_YEAR: {
                    startDate = DateUtils.addMonths(date, -6);
                    break;
                }
                case Model.CHECK_BILL_ONE_YEAR: {
                    startDate = DateUtils.addYears(date, -1);
                    break;
                }
            }
            countParam.setStartDate(startDate);
            countParam.setEndDate(date);
        }
        log.info("countParam:{}", ServiceUtils.toJson(countParam));
        List<ProviderNotificationDTO> dtos = providerNotificationMapper.countPayInfo(countParam);
        return getResult(dtos, countParam);
    }

    private Map<String, Object> getResult(List<ProviderNotificationDTO> dtos, CountParam countParam) {
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isEmpty(countParam.getDateType())) {
            map.put("notificationMap", dtos);
        }
        map.put("totalNum", dtos.size());
        Map<String, Object> last = new HashMap<>();
        Map<String, BillDTO<ProviderNotificationDTO>> result = new HashMap<>();
        double totalFee = 0;
        Calendar calendar = Calendar.getInstance();
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        Calendar calendar3 = Calendar.getInstance();
        if(countParam.getStartDate()!=null){
            calendar1.setTime(countParam.getStartDate());
            calendar3.setTime(countParam.getStartDate());
        }
        if(countParam.getEndDate()!=null) {
            calendar2.setTime(countParam.getEndDate());
        }
        if (Objects.nonNull(dtos)) {
            Boolean status = true;
            for (int i = 0; i < dtos.size(); i++) {
                if (dtos.get(i).getTotalFee() != null) {
                    totalFee += dtos.get(i).getTotalFee();
                }
                if (Objects.nonNull(dtos.get(i).getOrderDTO())) {
                    List<OrderDetail> orderDetails = orderDetailRepository.findByOrderId(
                            dtos.get(i).getOrderDTO().getOrderId()
                    );
                    dtos.get(i).setOrderDetails(orderDetails);
                }
                if (StringUtils.isNotEmpty(countParam.getDateType())) {
                    List<ProviderNotificationDTO> list = new ArrayList<>();
                    switch (countParam.getDateType()) {
                        case Model.DATE_TYPE_HOUR: {
                            if (status) {
                                int startHour = calendar1.get(Calendar.HOUR_OF_DAY);
                                int endHour = calendar2.get(Calendar.HOUR_OF_DAY);
                                int startDay = calendar1.get(Calendar.DAY_OF_MONTH);
                                int endDay = calendar2.get(Calendar.DAY_OF_MONTH);
                                int countDay = endDay - startDay;
                                //如果选择时间段不在一天内
                                if (countDay > 0) {
                                    for (int m = startHour; m < endHour - startHour + 24 * countDay; m++) {
                                        if (m / 24 > 0) {
                                            int day = startDay + m / 24;
                                            int hour = m % 24;
                                            result.put(day + "日" + formatTime(hour) + "时", null);
                                        } else {
                                            result.put(startDay + "日" + formatTime(m) + "时", null);
                                        }
                                    }
                                } else {
                                    for (int j = startHour; j <= endHour; j++) {
                                        result.put(startDay + "日" + formatTime(j) + "时", null);
                                    }
                                }
                                status = false;
                            }
                            if (dtos.get(i).getCreateTime() != null) {
                                calendar.setTime(dtos.get(i).getCreateTime());
                                int hour = calendar.get(Calendar.HOUR_OF_DAY);
                                int day = calendar.get(Calendar.DAY_OF_MONTH);
                                String key = day + "日" + formatTime(hour) + "时";
                                result = initResultMap(key, result, dtos, list, i);
                            }
                            break;
                        }
                        case Model.DATE_TYPE_DAY: {
                            if (status) {
                                int startDay = calendar1.get(Calendar.DAY_OF_MONTH);
                                int endDay = calendar2.get(Calendar.DAY_OF_MONTH);
                                int startMonth = calendar1.get(Calendar.MONTH) + 1;
                                int endMonth = calendar2.get(Calendar.MONTH) + 1;
                                int countMonth = endMonth - startMonth;
                                int daysOfMonths = calendar3.getActualMaximum(Calendar.DAY_OF_MONTH);
                                if (countMonth > 0) {
                                    for (int m = startDay; m <= endDay - startDay + daysOfMonths * countMonth; m++) {
                                        if (m / daysOfMonths > 0) {
                                            int day = m / daysOfMonths;
                                            int month = startMonth + m / daysOfMonths;
                                            result.put(month + "月" + formatTime(day) + "日", null);
                                            calendar3.set(Calendar.MONTH, month - 1);
                                            daysOfMonths = calendar3.getActualMaximum(Calendar.DAY_OF_MONTH);
                                        } else {
                                            result.put(startMonth + "月" + formatTime(m) + "日", null);
                                        }
                                    }
                                } else {
                                    for (int j = startDay; j <= endDay; j++) {
                                        result.put(startMonth + "月" + formatTime(j) + "日", null);
                                    }
                                }

                                status = false;
                            }
                            if (dtos.get(i).getCreateTime() != null) {
                                calendar.setTime(dtos.get(i).getCreateTime());
                                int day = calendar.get(Calendar.DAY_OF_MONTH);
                                int month = calendar.get(Calendar.MONTH) + 1;
                                String key = month + "月" + formatTime(day) + "日";
                                result = initResultMap(key, result, dtos, list, i);
                            }
                            break;
                        }
                        case Model.DATE_TYPE_WEEK: {
                            if (status) {
                                int startWeek = calendar1.get(Calendar.DAY_OF_WEEK);
                                int endWeek = calendar2.get(Calendar.DAY_OF_WEEK);
                                int startWeeksOfDays = calendar1.get(Calendar.WEEK_OF_MONTH);
                                int endWeeksOfDays = calendar2.get(Calendar.WEEK_OF_MONTH);
                                int countDay = (endWeeksOfDays - startWeeksOfDays);
                                int startDay=calendar1.get(Calendar.DAY_OF_MONTH);
                                if (countDay > 0) {
                                    for (int m = startWeek; m <= endWeek + 7 * countDay; m++) {
                                        if (m / 8 > 0) {
                                            int week = m % 7;
                                            String weekend = convertWeek(week-1);
                                            result.put(formatTime(startDay++) + "日" + weekend, null);
                                        } else {
                                            String weekend = convertWeek(m - 1);
                                            result.put(formatTime(startDay++) + "日" + weekend, null);
                                        }
                                    }
                                } else {
                                    for (int j = startWeek; j <= endWeek; j++) {
                                        String weekend = convertWeek(j - 1);
                                        result.put(formatTime(startDay++) + "日" + weekend, null);
                                    }
                                }
                                status = false;
                            }
                            if (dtos.get(i).getCreateTime() != null) {
                                calendar.setTime(dtos.get(i).getCreateTime());
                                int week = calendar.get(Calendar.DAY_OF_WEEK);
                                int day = calendar.get(Calendar.DAY_OF_MONTH);
                                String weekend = convertWeek(week - 1);
                                String key = formatTime(day) + "日" + weekend;
                                result = initResultMap(key, result, dtos, list, i);
                            }
                            break;
                        }
                        case Model.DATE_TYPE_MONTH: {
                            if (status) {
                                int startMonth = calendar1.get(Calendar.MONTH)+1;
                                int endMonth = calendar2.get(Calendar.MONTH)+1;
                                int startYear = calendar1.get(Calendar.YEAR);
                                int endDaYear = calendar2.get(Calendar.YEAR);
                                int countYear = endDaYear - startYear;
                                if (countYear > 0) {
                                    for (int m = startMonth; m <= endMonth + 12 * countYear; m++) {
                                        if (m / 13 > 0) {
                                            int year = startYear + m / 12;
                                            int month = m % 12;
                                            result.put(year + "年" + formatTime(month) + "月", null);
                                        } else {
                                            result.put(startYear + "年" + formatTime(m) + "月", null);
                                        }
                                    }
                                } else {
                                    for (int j = startMonth; j <= endMonth; j++)
                                        result.put(startYear + "年" + formatTime(j) + "月", null);
                                }
                                status = false;
                            }
                            if (dtos.get(i).getCreateTime() != null) {
                                calendar.setTime(dtos.get(i).getCreateTime());
                                int month = calendar.get(Calendar.MONTH) + 1;
                                int year = calendar.get(Calendar.YEAR);
                                String key = year + "年" + formatTime(month) + "月";
                                result = initResultMap(key, result, dtos, list, i);
                            }
                            break;
                        }
                    }
                }
            }
        }
        map.put("amount", new BigDecimal(totalFee).movePointLeft(2).toString());
        //TODO 退款总金额,笔数,实际收款金额
        map.put("balance", new BigDecimal(totalFee).movePointLeft(2).toString());
        if(result!=null){
            last.put("resultList", sortMapByKey(result));
            map.putAll(last);
        }

        Bussiness bussiness = bussinessRepository.getOne(countParam.getBusinessId());
        if (Objects.nonNull(bussiness)) {
            map.put("bussinessId", bussiness.getBussinessId());
            map.put("bussinessAdress", bussiness.getBussinessAddress());
            map.put("bussinessName", bussiness.getBussinessName());

        }
        return map;
    }

    private String convertWeek(int week) {
        if (week == 0) {
            return "星期天";
        } else if (week == 1) {
            return "星期一";
        } else if (week == 2) {
            return "星期二";
        } else if (week == 3) {
            return "星期三";
        } else if (week == 4) {
            return "星期四";
        } else if (week == 5) {
            return "星期五";
        } else {
            return "星期六";
        }
    }

    private static Map<String, BillDTO<ProviderNotificationDTO>> sortMapByKey(Map<String, BillDTO<ProviderNotificationDTO>> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }

        Map<String, BillDTO<ProviderNotificationDTO>> sortMap = new TreeMap<String, BillDTO<ProviderNotificationDTO>>(
                new MapKeyComparatorUtil());

        sortMap.putAll(map);

        return sortMap;
    }

    private String formatTime(int time) {
        return time < 10 ? "0" + time : String.valueOf(time);

    }

    private Map<String, BillDTO<ProviderNotificationDTO>> initResultMap(String key,
                                                                        Map<String, BillDTO<ProviderNotificationDTO>> result,
                                                                        List<ProviderNotificationDTO> dtos,
                                                                        List<ProviderNotificationDTO> list,
                                                                        int i) {
        if (Objects.isNull(result.get(key))
                || result.get(key) == null) {
            BillDTO<ProviderNotificationDTO> billDTO = new BillDTO<>();
            billDTO.setNum(1);
            if (dtos.get(i).getTotalFee() != null) {
                billDTO.setTotalFee(new BigDecimal(dtos.get(i).getTotalFee()).movePointLeft(2).doubleValue());
            }
            list.add(dtos.get(i));
            billDTO.setT(list);
            result.put(key, billDTO);
        } else {
            result.get(key).getT().add(dtos.get(i));
            int size = result.get(key).getT().size();
            result.get(key).setNum(size);
            if (dtos.get(i).getTotalFee() != null) {
                Double singleFee = result.get(key).getTotalFee() + (new BigDecimal(dtos.get(i).getTotalFee()).movePointLeft(2).doubleValue());
                result.get(key).setTotalFee(singleFee);
            }
        }
        return result;
    }


}
